#!/usr/bin/env python2

#FTDI USB Device Emulator
#by Travis Goodspeed

import sys;
import binascii;
import array;
import time;

from GoodFETMAXUSB import *;

class GoodFETMAXUSBFTDI(GoodFETMAXUSBDevice):
    """This emulates the FTDI USB to Serial chips."""
    def hidinit(self):
        """Initialize a USB FTDI device."""
        self.usb_disconnect();
        time.sleep(1);
	self.usb_connect();
        self.ftdirun();
        
    def ftdirun(self):
        """Main loop of the USB FTDI emulator."""
        print "Starting a FTDI device.  This won't return.";
        while 1:
            self.service_irqs();
            #self.typeletter_empty();
    def do_SETUP(self):
        """Handle USB Enumeration"""
        
        #Grab the SETUP packet from the buffer.
        SUD=self.readbytes(rSUDFIFO,8);
        
        #Parse the SETUP packet
        print "Handling a setup packet of %s" % self.setup2str(SUD);
        setuptype=(ord(SUD[bmRequestType])&0x60);
        if setuptype==0x00:
            self.std_request(SUD);
        elif setuptype==0x20:
            self.class_request(SUD);
        elif setuptype==0x40:
            self.vendor_request(SUD);
        else:
            print "Unknown request type 0x%02x." % ord(SUD[bmRequestType])
            self.STALL_EP0(SUD);
    def ftdi_request(self,SUD):
        """Handle an FTDI request."""
        
    def class_request(self,SUD):
        """Handle a class request."""
        print "Stalling a class request.";
        self.STALL_EP0(SUD);
    def vendor_request(self,SUD):
        """Handle an FTDI vendor request."""
        request=ord(SUD[bRequest]);
        
        if request==0:   #reset
            pass
        elif request==1: #modem_ctrl
            valuel=ord(SUD[wValueL])
            valueh=ord(SUD[wValueH]);
            dtr=valuel&1;
            rts=(valuel&2)>>1;
            dtren=valueh&1;
            rtsen=(valueh&2)>>1;
            
            if dtren: print "DTR is enabled, value %i" % dtr;
            if rtsen: print "RTS is enabled, value %i" % rts;
            
            pass;
        elif request==2: #set_flow_ctrl
            indexh=ord(SUD[wIndexH]);
            indexl=ord(SUD[wIndexL]);
            if indexh==0:
                print "SET_FLOW_CTRL to no handshaking.";
            if indexl&1:
                print "SET_FLOW_CTRL for RTS/CTS handshaking.";
            if indexl&2:
                print "SET_FLOW_CTRL for DTR/DSR handshaking.";
            if indexl&4:
                print "SET_FLOW_CTRL for XON/XOFF handshaking.";
            
            pass;
        elif request==3: #set_baud_rate
            print "Baud rate set to %i." % ord(SUD[wValueL]);
            pass;
        elif request==4: #set_data
            pass;
        elif request==5: #get_status
            print "I don't know how to send the status.";
            pass; #FIXME
        elif request==6: #set_event_char
            pass;
        elif request==7: #set_error_char
            pass;
        elif request==9: #set_latency_timer
            print "Expected to set latency timer to 0x%02x." % ord(SUD[wValueL]);
            pass;
        elif request==0x0a: #get_latency_timer
            print "Bullshitting a value for the latency timer."
            #Send some sort of reply.
            self.wreg(rEP0FIFO,0x01);
            #self.wreg(rEP0FIFO,0x00);
            self.wregAS(rEP0BC,1);
            #Don't send reply twice.
            return;
            
        
        print "Blindly accepting unhandled vendor request %02x" % request;
        self.wregAS(rEP0BC,0);
    def std_request(self,SUD):
        """Handles a standard setup request."""
        setuptype=ord(SUD[bRequest]);
        if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD);
        #elif setuptype==SR_SET_FEATURE: self.feature(1);
        elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD);
        elif setuptype==SR_GET_STATUS: self.get_status(SUD);
        elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
        elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
        else:
            print "Stalling Unknown standard setup request type %02x" % setuptype;
            self.STALL_EP0(SUD);
    
    def get_interface(self,SUD):
        """Handles a setup request for SR_GET_INTERFACE."""
        if ord(SUD[wIndexL]==0):
            self.wreg(rEP0FIFO,0);
            self.wregAS(rEP0BC,1);
        else:
            self.STALL_EP0(SUD);
    

#0403:6001

#Device Descriptor
    DD=[0x12,	       		# bLength = 18d
        0x01,			# bDescriptorType = Device (1)
        0x10,0x01,		# bcdUSB(L/H) USB spec rev (BCD)
	0x00,0x00,0x00, 	# bDeviceClass, bDeviceSubClass, bDeviceProtocol
	0x40,			# bMaxPacketSize0 EP0 is 64 bytes
	0x03,0x04,		# idVendor(L/H)--FTDI is 0403
	0x72,0x83,		# idProduct(L/H)--6001
	0x01,0x00,		# bcdDevice--1234
	1,2,3,			# iManufacturer, iProduct, iSerialNumber
	1                       # One configuration.
        ];
#Configuration Descriptor
    CD=[0x09,			# bLength
	0x02,			# bDescriptorType = Config
	0x20,0x00,		# wTotalLength(L/H) = 34 bytes (0x22)
	0x01,			# bNumInterfaces
	0x01,			# bConfigValue
	0x00,			# iConfiguration
	0xE0,			# bmAttributes. b7=1 b6=self-powered b5=RWU supported
	0x01,			# MaxPower is 2 ma
# INTERFACE Descriptor
	0x09,			# length = 9
	0x04,			# type = IF
	0x00,			# IF #0
	0x00,			# bAlternate Setting
	0x02,			# bNum Endpoints
	0xFF,			# bInterfaceClass = FF=vendor
	0xFF,0xFF,		# bInterfaceSubClass, bInterfaceProtocol
	0x02,			# iInterface
# IN Endpoint Descriptor
	0x07,			# bLength
	0x05,			# bDescriptorType (Endpoint)
	0x83,			# bEndpointAddress (EP3-IN)		
        0x02,			# bmAttributes	(bulk)
	64,0,                   # wMaxPacketSize (64)
	00,
# OUT Endpoint Descriptor
	0x07,			# bLength
	0x05,			# bDescriptorType (Endpoint)
	0x01,			# bEndpointAddress (EP1-OUT)		
        0x02,			# bmAttributes	(bulk)
	64,0,                   # wMaxPacketSize (64)
	00];
    strDesc=[
# STRING descriptor 0--Language string
"\x04\x03\x09\x04",
# [
#         0x04,			# bLength
# 	0x03,			# bDescriptorType = string
# 	0x09,0x04		# wLANGID(L/H) = English-United Sates
# ],
# STRING descriptor 1--Manufacturer ID
"\x10\x03G\x00o\x00o\x00d\x00F\x00E\x00T\x00",
# STRING descriptor 2 - Product ID
"\x18\x03F\x00T\x00D\x00I\x00 \x00E\x00m\x00u\x00l\x00a\x00t\x00o\x00r\x00 \x00 \x00 \x00 \x00 \x00",
# STRING descriptor 3 - Serial Number ID
"\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
];


    def set_configuration(self,SUD):
        """Set the configuration."""
        bmSUSPIE=0x10;
        configval=ord(SUD[wValueL]);
        if(configval>0):
            self.SETBIT(rUSBIEN,bmSUSPIE);
        self.rregAS(rFNADDR);
    def get_status(self,SUD):
        """Get the USB Setup Status."""
        testbyte=ord(SUD[bmRequestType])
        
        #Toward Device
        if testbyte==0x80:
            self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
            self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
            self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
        #Toward Interface
        elif testbyte==0x81:
            self.wreg(rEP0FIFO,0x00);
            self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
            self.wregAS(rEP0BC,2);
        #Toward Endpoint
        elif testbyte==0x82:
            if(ord(SUD[wIndexL])==0x83):
                self.wreg(rEP0FIFO,0x01); #Stall EP3
                self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
                self.wregAS(rEP0BC,2);
            else:
                self.STALL_EP0(SUD);
        else:
            self.STALL_EP0(SUD);
    def service_irqs(self):
        """Handle USB interrupt events."""
        
        epirq=self.rreg(rEPIRQ);
        usbirq=self.rreg(rUSBIRQ);
        
        #Are we being asked for setup data?
        if(epirq&bmSUDAVIRQ): #Setup Data Requested
            self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit
            self.do_SETUP();
        elif(epirq&bmIN3BAVIRQ): #EN3-IN packet
            self.do_IN3();
            #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
        elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet
            self.do_OUT1();
            self.wregAS(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing.
        #else:
        #    self.do_IN3();
    
    typestring="GoodFET emulates FTDI properly, if you can read this!\n";
    typepos=0;
    
    def type_IN3(self):
        """Type next letter in buffer."""
        if self.typepos>=len(self.typestring):
            self.typepos=0;
            self.typeletter(' ');
        else:
            self.typeletter(self.typestring[self.typepos]);
            self.typepos=self.typepos+1;
        return;
    def typeletter(self,key):
        """Type a letter on IN3.  Zero for keyup."""
        if type(key)==str: key=ord(key);
        
        self.wreg(rEP3INFIFO,0x01);      #Modem Status
        self.wreg(rEP3INFIFO,0x00);      #Line Status
        self.wreg(rEP3INFIFO,key);
        self.wregAS(rEP3INBC,3);
    def do_IN3(self):
        """Handle IN3 input event."""
        #Don't bother clearing interrupt flag, that's done by sending the reply.
        self.type_IN3();
    def do_OUT1(self):
        """Handle an OUT1 output event."""
        print "Got an output event, printing the result.";
        l=self.rreg(rEP1OUTBC);
        frame=self.readbytesAS(rEP1OUTFIFO,l);
        print "FTDI OUT: %s" % frame[1:len(frame)];
        #self.type_IN3();

#Initialize FET and set baud rate
client=GoodFETMAXUSBFTDI();
client.serInit()


client.MAXUSBsetup();
client.hidinit();

